// 
// driver2
//
// Template test harness for demo shaders.
//

#include <math.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>


#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif


#include "ShaderSetup.h"

int windowHeight = 500;	// Current height of window
int windowWidth  = 500;	// Current width of window

GLUquadricObj *cube = NULL;

GLuint phong_program;
 
// Muted material properties
GLfloat ad_red[]   = { 0.6, 0.0, 0.0, 1.0 };
GLfloat ad_green[] = { 0.0, 0.6, 0.2, 1.0 };
GLfloat ad_blue[]  = { 0.0, 0.0, 0.7, 1.0 };

// Pure material properties
// GLfloat ad_red[]   = { 1.0, 0.0, 0.0, 1.0 };
// GLfloat ad_green[] = { 0.0, 1.0, 0.0, 1.0 };
// GLfloat ad_blue[]  = { 0.0, 0.0, 1.0, 1.0 };

GLfloat spec[] = { 1.0, 1.0, 1.0, 1.0 };

GLint shiny1 = 10;
GLint shiny2 = 40;
GLint shiny3 = 70;

#ifdef __cplusplus
extern "C" {
#endif

//
// Display callback function - used for redisplay as well
//
//  This function draws the scene.  It will also apply the shader and
//  attach it to the correct primitive.  For sake of the example, the
//  shader will be applied to the wall.
//

void display( void ) {

	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glMaterialfv( GL_FRONT, GL_SPECULAR, spec );

	glUseProgram( phong_program );

	// draw a red cube
	// create it if it doesn't already exist
	glPushMatrix();
		glRotatef( 60, 1, 0, 0 );
		glRotatef( 60, 0, 1, 0 );
		glRotatef( 60, 0, 0, 1 );
		glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ad_red );
		glMateriali( GL_FRONT, GL_SHININESS, shiny1 );
		glutSolidCube( 2.0 );
	glPopMatrix();
	
	glutSwapBuffers();

}


//
// Callback function for screen window resizing/reshaping
//

void reshape( int width, int height ) {

	glViewport( 0, 0, width, height );
	windowWidth = width;
	windowHeight = height;

}

//
// Callback function for keyboard input
//
// Ignores all input except 'q', 'Q', and ESC
//

void keyboard( unsigned char key, int x, int y ) {

	switch( key ) {

		case 'q': case 'Q': case 033:
			exit( EXIT_SUCCESS );
	
	}

}

#ifdef __cplusplus
}
#endif

// Light properties

GLfloat pos[] = { 10.0, 10.0, 0.0, 0.0 };
GLfloat amb[] = { 0.4, 0.4, 0.4, 1.0 };

void init( void ) {
	
	// rendering mode
	glShadeModel( GL_SMOOTH );
	glClearColor( 0.0, 0.0, 0.0, 0.5 );
	glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
	
	// enable depth testing
	glEnable( GL_DEPTH_TEST ); 
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	
	// Camera stuff - matrix initialization
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	gluPerspective( 45, 1.0, 1.0, 100.0 );
	
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	gluLookAt( 0.0, 0.0, 12.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );

	// switch on the light
	glEnable( GL_LIGHTING );
	glLightfv( GL_LIGHT0, GL_AMBIENT, amb );
	glLightModelfv( GL_LIGHT_MODEL_AMBIENT, amb );
	glLightfv( GL_LIGHT0, GL_POSITION, pos );
	glEnable( GL_LIGHT0 );

	// set up the shaders
	phong_program = ShaderSetup( "phong.vert", "phong.frag" );
	if( phong_program == 0 ) {
		fputs( "Error in shader setup - exiting\n", stderr );
		exit( EXIT_FAILURE );
	}

}


//
// Main routine - GLUT setup and initialization
//

int main( int argc, char **argv ) {
	
	// Initialize GLUT
	glutInit( &argc, argv );
	
	// Enable double buffering and depth buffering
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
	glutInitWindowSize( windowWidth, windowHeight );
	glutCreateWindow( "Shader Test Program 2" );
	
	// Callback functions
	glutReshapeFunc( reshape );
	glutDisplayFunc( display );
	glutKeyboardFunc( keyboard );
	
	init();

	// enter your display loop.
	glutMainLoop();
	
	return 0;

}
